package com.czy.workflow.core.executor;

import com.czy.workflow.core.context.FlowContext;
import com.czy.workflow.core.exception.FlowException;
import com.czy.workflow.core.exception.FlowNodeOperationInvalidException;
import com.czy.workflow.core.model.FlowBranch;
import com.czy.workflow.core.model.FlowNode;
import com.czy.workflow.core.model.TaskInfo;

import java.util.List;
import java.util.logging.Logger;

public abstract class AbstractTaskExecutor implements TaskExecutor {

    Logger logger = Logger.getLogger(AbstractTaskExecutor.class.getName());

    FlowContext flowContext;

    ThreadLocal<TaskInfo> threadLocal = new ThreadLocal<>();

    TaskInfo taskInfoInit;


    /**
     * 执行自定义（注解）任务
     * @param taskInfo
     * @return 自定义方法的结果，如果没有则默认为true
     */
    public abstract boolean invokeExecutorComponent(TaskInfo taskInfo);


    /**
     * 执行配置流程任务
     * @param taskInfo
     * @return
     * @throws FlowException
     */
    public abstract boolean executeNodeTask(TaskInfo taskInfo) throws FlowException;

    /**
     * 校验当前节点
     * @param taskInfo
     * @return
     * @throws FlowException
     */
    public abstract boolean checkCurrentNode(TaskInfo taskInfo) throws FlowException;


    /**
     * 准备下一节点，并缓存
     * @param taskInfo
     * @return
     */
    public abstract List<FlowNode> prepareNextNode(TaskInfo taskInfo, List<FlowBranch> nodeBranches) throws FlowException;

    /**
     * @param taskInfo
     * @return
     * @throws FlowException
     */
    @Override
    public boolean execute(TaskInfo taskInfo) throws FlowException{
        logger.info(String.format("------ current node -> [%s, %s] ------", taskInfo.getFlowCode(), taskInfo.getNode().getCode()));

        if(!this.checkCurrentNode(taskInfo)){
            throw new FlowNodeOperationInvalidException(taskInfo);
        }


        flowContext.getTaskListenerNotify().before(taskInfo, true);

        //先调用用户自定义节点任务
        boolean result = this.invokeExecutorComponent(taskInfo);
        if(result){
            //再执行配置流程
            this.executeNodeTask(taskInfo);
        }

        flowContext.getTaskListenerNotify().after(taskInfo, result);

        return result;
    }

    @Override
    public void run() {
        //使用线程模式执行
        try {
            threadLocal.set(this.taskInfoInit);
            this.execute(this.taskInfoInit);
        } catch (FlowException e) {
            e.printStackTrace();
        }
    }


    @Override
    public void setFlowContext(FlowContext flowContext) {
        this.flowContext = flowContext;
    }




    public void setTaskInfo(TaskInfo taskInfo){
        this.taskInfoInit = taskInfo;
    }
}
